1 /** 2 * Authors: Pedro Tacla Yamada 3 * Date: June 9, 2014 4 * License: Licensed under the MIT license. See LICENSE for more information 5 * Version: 1.0.2 6 */ 7 module colorize.colors; 8 9 import std..string : format; 10 11 shared bool _useColors; 12 13 void forceColors() @trusted { 14 synchronized { 15 _useColors = true; 16 } 17 } 18 19 shared static this() { 20 import std.stdio : stdout; 21 22 version (unittest) 23 _useColors = true; 24 else { 25 version (Windows) { 26 _useColors = false; 27 } else { 28 import core.sys.posix.unistd : isatty; 29 30 _useColors = isatty(stdout.fileno) == 1; 31 } 32 } 33 } 34 35 private template color_type(int offset) { 36 static enum type : int { 37 init_ = 39 + offset, 38 39 black = 30 + offset, 40 red = 31 + offset, 41 green = 32 + offset, 42 yellow = 33 + offset, 43 blue = 34 + offset, 44 magenta = 35 + offset, 45 cyan = 36 + offset, 46 white = 37 + offset, 47 48 light_black = 90 + offset, 49 light_red = 91 + offset, 50 light_green = 92 + offset, 51 light_yellow = 93 + offset, 52 light_blue = 94 + offset, 53 light_magenta = 95 + offset, 54 light_cyan = 96 + offset, 55 light_white = 97 + offset 56 } 57 } 58 59 alias fg = color_type!0.type; 60 alias bg = color_type!10.type; 61 62 // Text modes 63 static enum mode : int { 64 init_ = 0, 65 bold = 1, 66 underline = 4, 67 blink = 5, 68 swap = 7, 69 hide = 8 70 } 71 72 /** 73 * Wraps a string around color escape sequences. 74 * 75 * Params: 76 * str = The string to wrap with colors and modes 77 * c = The foreground color (see the fg enum type) 78 * b = The background color (see the bg enum type) 79 * m = The text mode (see the mode enum type) 80 * Example: 81 * --- 82 * writeln("This is blue".color(fg.blue)); 83 * writeln( 84 * color("This is red over green blinking", fg.blue, bg.green, mode.blink) 85 * ); 86 * --- 87 */ 88 string color(const string str, const fg c = fg.init_, const bg b = bg.init_, const mode m = mode 89 .init_) @trusted { 90 if (_useColors) { 91 return format("\033[%d;%d;%dm%s\033[0m", m, c, b, str); 92 } 93 94 return str; 95 } 96 97 unittest { 98 string ret; 99 100 ret = "This is yellow".color(fg.yellow); 101 assert(ret == "\033[33mThis is yellow\033[0m"); 102 103 ret = "This is light green".color(fg.light_green); 104 assert(ret == "\033[92mThis is light green\033[0m"); 105 106 ret = "This is light blue with red background".color(fg.light_blue, bg.red); 107 assert(ret == "\033[0;94;41mThis is light blue with red background\033[0m"); 108 109 ret = "This is red on blue blinking".color(fg.red, bg.blue, mode.blink); 110 assert(ret == "\033[5;31;44mThis is red on blue blinking\033[0m"); 111 112 ret = color("This is magenta", "magenta"); 113 assert(ret == "\033[35mThis is magenta\033[0m"); 114 } 115 116 string colorHelper(const string str, const string name) pure { 117 int code; 118 119 switch (name) { 120 case "init_": 121 code = 39; 122 break; 123 124 case "black": 125 code = 30; 126 break; 127 case "red": 128 code = 31; 129 break; 130 case "green": 131 code = 32; 132 break; 133 case "yellow": 134 code = 33; 135 break; 136 case "blue": 137 code = 34; 138 break; 139 case "magenta": 140 code = 35; 141 break; 142 case "cyan": 143 code = 36; 144 break; 145 case "white": 146 code = 37; 147 break; 148 149 case "light_black": 150 code = 90; 151 break; 152 case "light_red": 153 code = 91; 154 break; 155 case "light_green": 156 code = 92; 157 break; 158 case "light_yellow": 159 code = 93; 160 break; 161 case "light_blue": 162 code = 94; 163 break; 164 case "light_magenta": 165 code = 95; 166 break; 167 case "light_cyan": 168 code = 96; 169 break; 170 case "light_white": 171 code = 97; 172 break; 173 174 case "bg_init": 175 code = 49; 176 break; 177 178 case "bg_black": 179 code = 40; 180 break; 181 case "bg_red": 182 code = 41; 183 break; 184 case "bg_green": 185 code = 42; 186 break; 187 case "bg_yellow": 188 code = 43; 189 break; 190 case "bg_blue": 191 code = 44; 192 break; 193 case "bg_magenta": 194 code = 45; 195 break; 196 case "bg_cyan": 197 code = 46; 198 break; 199 case "bg_white": 200 code = 47; 201 break; 202 203 case "bg_light_black": 204 code = 100; 205 break; 206 case "bg_light_red": 207 code = 101; 208 break; 209 case "bg_light_green": 210 code = 102; 211 break; 212 case "bg_light_yellow": 213 code = 103; 214 break; 215 case "bg_light_blue": 216 code = 104; 217 break; 218 case "bg_light_magenta": 219 code = 105; 220 break; 221 case "bg_light_cyan": 222 code = 106; 223 break; 224 case "bg_light_white": 225 code = 107; 226 break; 227 228 case "mode_init": 229 code = 0; 230 break; 231 case "mode_bold": 232 code = 1; 233 break; 234 case "mode_underline": 235 code = 4; 236 break; 237 case "mode_blink": 238 code = 5; 239 break; 240 case "mode_swap": 241 code = 7; 242 break; 243 case "mode_hide": 244 code = 8; 245 break; 246 247 default: 248 throw new Exception("Unknown fg color, bg color or mode \"" ~ name ~ "\""); 249 } 250 251 return format("\033[%dm%s\033[0m", code, str); 252 } 253 254 string colorHelper(T)(const string str, const T t = T.init_) pure @safe 255 if (is(T : fg) || is(T : bg) || is(T : mode)) { 256 return format("\033[%dm%s\033[0m", t, str); 257 } 258 259 alias background = colorHelper!bg; 260 alias foreground = colorHelper!fg; 261 alias style = colorHelper!mode; 262 263 alias color = background; 264 alias color = foreground; 265 alias color = style; 266 alias color = colorHelper; 267 268 unittest { 269 string ret; 270 271 ret = "This is red on blue blinking".foreground(fg.red).background(bg.blue).style(mode.blink); 272 273 assert(ret == "\033[5m\033[44m\033[31mThis is red on blue blinking\033[0m\033[0m\033[0m"); 274 }